package generics;

import java.util.*;

import static net.mindview.util.Print.*;

interface Factory<T> {
    T create();
}

class Building {
}

class House extends Building {
}

class BuildingFactory implements Factory<Building> {
    @Override
    public Building create() {
        return new Building();
    }
}

class HouseFactory implements Factory<House> {
    @Override
    public House create() {
        return new House();
    }
}

public class ClassTypeCapture24<T> {
    Class<?> kind;
    Map<String, Factory> map;

    public ClassTypeCapture24(Class<?> kind) {
        this.kind = kind;
    }

    public ClassTypeCapture24(Class<?> kind, Map<String, Factory> map) {
        this.kind = kind;
        this.map = map;
    }

    public boolean f(Object arg) {
        return kind.isInstance(arg);
    }

    public void addType(String typename, Factory factory) {
        map.put(typename, factory);
    }

    public Object createNew(String typename) throws
            IllegalAccessException, InstantiationException {
        if (map.containsKey(typename))
            return map.get(typename).create();
        System.out.println(typename + " class not available");
        return null;
    }

    public static void main(String[] args) {
        ClassTypeCapture24<Building> ctt1 = new ClassTypeCapture24<Building>(Building.class);
        System.out.println(ctt1.f(new Building()));
        System.out.println(ctt1.f(new House()));
        ClassTypeCapture24<House> ctt2 = new ClassTypeCapture24<House>(House.class);
        System.out.println(ctt2.f(new Building()));
        System.out.println(ctt2.f(new House()));
        ClassTypeCapture24<Building> ct =
                new ClassTypeCapture24<Building>(Building.class, new HashMap<String, Factory>());
        ct.addType("House", new HouseFactory());
        ct.addType("Building", new BuildingFactory());
        System.out.println("ct.map = " + ct.map);
        try {
            Building b = (Building) ct.createNew("Building");
            House h=(House)ct.createNew("House");
            System.out.println("b.getClass().getName(): "+b.getClass().getName());
            System.out.println("h.getClass().getName()"+h.getClass().getName());
            System.out.println("House h is istance House: "+(h instanceof House));
            System.out.println("Building b is instance of House"+(b instanceof House));
        } catch (IllegalAccessException e) {
            System.out.println("IllegalAccessException in main");
        } catch (InstantiationException e) {
            System.out.println("InstantiationException in main");
        }

    }
}
